//
//  ServerChooseViewController.m
//  wAudioShare
//
//  Created by 赵帅 on 13-12-12.
//  Copyright (c) 2013年 赵帅. All rights reserved.
//
#import <netinet/in.h>
#import <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>

#import "pthread.h"

#import "ServerChooseViewController.h"
#import "DemoUpnpViewController.h"
#import "RemoteControlViewController.h"

#import "WISInterfaces.h"
#import "wis.h"
#import <netdb.h>
#import "MMProgressHUD.h"

#define BUFSIZE 4096

@interface ServerChooseViewController ()
{
    NSMutableArray * serverArray;
    
    unsigned long m_IP;
    int m_Port;
    int m_bRunning;
    
    NSThread * m_recvThread;
    NSTimer * remoteDeviceTimer;
    
    BOOL m_bRecreateThread;
}

@property (assign) IBOutlet UILabel * nameLabel;
@property (assign) IBOutlet UIImageView * descBack;
@property (assign) IBOutlet UITableView * serverTable;
@property (assign) IBOutlet UITextView * descTextView;

@property (retain) DemoUpnpViewController * upnpController;

@end

@implementation ServerChooseViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    
    serverArray = [[NSMutableArray alloc] initWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:@"WIS Server",@"name",@"http://wiimu.f3322.org:5678/wis/web/server.php",@"url", nil],[NSDictionary dictionaryWithObjectsAndKeys:@"Nietech WIS Server",@"name",@"http://www.evalogik.com:5678/wis/webuser/server.php",@"url", nil], nil];
    
    UIImage *image = [UIImage imageNamed:@"demo_field_back.png"];
    image = [image stretchableImageWithLeftCapWidth:floorf(image.size.width/2) topCapHeight:floorf(image.size.height/2)];
    _descBack.image = image;

    m_bRunning = 1;
    m_bRecreateThread = NO;
    
    //_nameLabel.text = [self getUniqueID];
    
    //mod by anson 14-03
    _nameLabel.text = [[GlobalInfo sharedInstance] getUniqueID];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)viewWillAppear:(BOOL)animated
{
    [self logText:@"请选择WIS Server"];
}

#pragma mark - navigation methods
-(NSString *)navigationBarTitle
{
    return @"WIS Demo";
}

-(IBAction)backButtonPressed:(id)sender
{
    if(remoteDeviceTimer != nil && [remoteDeviceTimer isValid])
    {
        [remoteDeviceTimer invalidate];
        remoteDeviceTimer = nil;
    }
    m_bRunning = NO;
    
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark -
#pragma mark UITableView Delegate & Datasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [serverArray count];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 45;
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
    }
    else
    {
        for(UIView * subview in [cell.contentView subviews])
        {
            [subview removeFromSuperview];
        }
    }
    
    NSDictionary * dic = [serverArray objectAtIndex:indexPath.row];
    
    cell.textLabel.text = [dic objectForKey:@"name"];
    cell.imageView.image = [UIImage imageNamed:@"server_icon"];
    
    // Configure the cell.
    
    
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:YES];

    _descTextView.text = @"获取server信息中...";
    
    [MMProgressHUD showWithStatus:@"loading..."];
    
    if([GlobalInfo sharedInstance].m_CmdSock != 0)
    {
        m_bRunning = NO;
    }
    
    double delayInSeconds = 1;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [[GlobalService sharedInstance] getWISAddress:self url:[[serverArray objectAtIndex:indexPath.row] objectForKey:@"url"]];
    });
}

-(void)serviceGetWISAddressCallBack:(NSDictionary*)dicCallBack
{
    if(![[dicCallBack objectForKey:@"responsestatus"] isEqualToString:SERVICE_SUCCESS])
    {
        _descTextView.text = @"获取server信息失败";
        [MMProgressHUD dismiss];
        return;
    }

    _descTextView.text = @"获取server信息成功";
    m_Port = [[dicCallBack objectForKey:@"port"] intValue];
    
    NSString * tempIP = [self getTrueIP:[dicCallBack objectForKey:@"host"]];
    
    m_IP = inet_addr([tempIP UTF8String]);
    
    [self performSelectorInBackground:@selector(attempToCreateThread) withObject:nil];
}

#pragma mark - private methods
- (BOOL)isPureInt:(NSString*)string{
    NSScanner* scan = [NSScanner scannerWithString:string];
    int val;
    return[scan scanInt:&val] && [scan isAtEnd];
}

-(NSString *)getTrueIP:(NSString *)host
{
    NSString * lastChar = [host substringFromIndex:[host length]-2];
    if([self isPureInt:lastChar])
    {
        return host;
    }
    else
    {
        NSString * hostStr = nil;
        if([host rangeOfString:@"http://"].location == NSNotFound)
        {
            hostStr = [NSString stringWithFormat:@"http://%@",host];
        }
        else
        {
            hostStr = host;
        }
        
        NSURL * url = [NSURL URLWithString:hostStr];
        char * str = (char *)[[url host] UTF8String];
        struct hostent *remoteHostEnt = gethostbyname(str);
        struct in_addr *remoteInAddr = (struct in_addr *) remoteHostEnt->h_addr_list[0];
        char *sRemoteInAddr = inet_ntoa(*remoteInAddr);
        NSString* hostIP = [NSString stringWithUTF8String:sRemoteInAddr];
        
        return hostIP;
    }
}

-(void)logText:(NSString *)log
{
    _descTextView.text = log;
}

-(void)enterUPNPController
{
    if([self.navigationController.topViewController isKindOfClass:[ServerChooseViewController class]])
    {
        self.upnpController = [[DemoUpnpViewController alloc] initWithNibName:@"DemoUpnpViewController" bundle:nil];
        [self.navigationController pushViewController:_upnpController animated:YES];
    }
}

-(void)popToRootWithError
{
    if(![self.navigationController.topViewController isKindOfClass:[ServerChooseViewController class]])
    {
        [self.view makeToast:@"连接失败"
                    duration:3.0
                    position:@"bottom"
                       title:@"提示"];
        
        [self.navigationController popToViewController:self animated:YES];
    }
}

-(void)TCPRun
{
    [self performSelectorOnMainThread:@selector(logText:) withObject:@"开始连接服务器" waitUntilDone:YES];
    
    int ret;
	int sock = 0;
	in_addr in;
	struct sockaddr_in localAddr;
	struct sockaddr_in server;
	struct timeval t;
	int error = 0;
	socklen_t errlen = sizeof(errlen);
	u_long iMode = 1;
	fd_set wrfds;
	fd_set rdfds;
    int reconnectTime = 0;
    
    WisSocketCmd *msg = ( WisSocketCmd *) malloc (MAX_WIS_DATA_LEN
                                                  + sizeof(WisSocketCmd));
	while(m_bRunning)
	{
		int handle = 0;
		int retry_count = 0;
        
		sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        
		localAddr.sin_family = AF_INET;
		localAddr.sin_addr.s_addr = INADDR_ANY;
		localAddr.sin_port = 0;
		ret = bind(sock, (struct sockaddr*)&localAddr, sizeof(localAddr));
		if (ret == -1)
		{
			printf("AMirrorClient::TcpRun bind  socket failed\r\n");
			goto RECONNECT;
		}
        
		ioctl(sock, FIONBIO, (u_long*)&iMode);
		{
			//int nSendBuf=65535;
			//setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char*)&nSendBuf,sizeof(int));
			//nSendBuf=65535;
			//setsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&nSendBuf,sizeof(int));
            //setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, , )
		}
        
        
		in.s_addr = m_IP;
        
		server.sin_family = AF_INET;
		server.sin_addr.s_addr = m_IP;
        server.sin_port = htons(m_Port);
		ret = connect(sock, (sockaddr*)&server, sizeof(server));
		if (ret == -1)
		{
			if(errno != EINPROGRESS)
			{
				printf("AMirrorClient::TcpRun connect socket return failed\r\n");
				goto RECONNECT;
			}
			
			while(m_bRunning) {
				FD_ZERO(&wrfds);
				FD_SET(sock, &wrfds);
                
				t.tv_sec  =2;
				t.tv_usec =0;
				ret = select(sock+1, 0, &wrfds, 0, &t);
				if(ret < 0) {
					printf("AMirrorClient::TcpRun connect select fail\r\n");
					goto RECONNECT;
				}
                
				if(getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &errlen) < 0)
				{
					printf("AMirrorClient::TcpRun connect getsockopt fail\n");
					goto RECONNECT;
				}
                
				if(error)
				{
					if(error == ETIMEDOUT)
						printf("AMirrorClient::TcpRun connect timeout\n");
					if(error == ECONNREFUSED)
						printf("AMirrorClient::TcpRun connect refused\n");
					else
						printf("AMirrorClient::TcpRun connect err=%d\n", error);
                    
					goto RECONNECT;
				}
				
				if(ret == 0) {
					if(retry_count++ > 15) {
						printf("AMirrorClient::TcpRun connect retry fail\r\n");
						goto RECONNECT;
					}

					continue;
				}
                
				if(FD_ISSET(sock, &wrfds)) {
					FD_CLR(sock, &wrfds);
					handle = sock;
					printf("AMirrorClient::TcpRun connect ok\r\n");
                    [GlobalInfo sharedInstance].m_CmdSock = handle;

                    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC));
                    
                    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                        //[WISInterfaces wis_send_login_cmd:[GlobalInfo sharedInstance].m_CmdSock name:(char *)[[self getUniqueID] UTF8String]];
                        
                        [WISInterfaces wis_send_login_cmd:[GlobalInfo sharedInstance].m_CmdSock name:(char *)[[[GlobalInfo sharedInstance] getUniqueID] UTF8String]];
                        
                       
                    });
					break;
				}
			}
		}
		else
		{
			printf("AMirrorClient::TcpRun connect direct ok\r\n");
			handle = sock;
            [GlobalInfo sharedInstance].m_CmdSock = handle;
            dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC));
            dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                //[WISInterfaces wis_send_login_cmd:[GlobalInfo sharedInstance].m_CmdSock name:(char *)[[self getUniqueID] UTF8String]];
                
                [WISInterfaces wis_send_login_cmd:[GlobalInfo sharedInstance].m_CmdSock name:(char *)[[[GlobalInfo sharedInstance] getUniqueID] UTF8String]];
                
            });
		}
        
		if(handle)
		{
            [GlobalInfo sharedInstance].m_CmdSock = handle;

			while(m_bRunning)
			{
				FD_ZERO(&rdfds);
				FD_SET(handle, &rdfds);
				
				t.tv_sec = 2;
				t.tv_usec = 0;
                
				ret = select(handle+1,&rdfds,0,0,&t);
				if(ret < 0)
				{
					printf("AMirrorClient::TcpRun recv select fail\n");
					goto RECONNECT;
				}
				
				if(ret == 0)
				{
					if(getsockopt(handle, SOL_SOCKET, SO_ERROR, &error, &errlen) < 0)
					{
						printf("AMirrorClient::TcpRun recv select getsockopt fail\n");
						goto RECONNECT;
					}
					
					if(error)
					{
						printf("AMirrorClient::TcpRun recv select  err=%d\n", error);
						goto RECONNECT;
					}
                    
					usleep(10000);
					continue;
				}
                
				if (FD_ISSET(handle, &rdfds))
				{
					FD_CLR(handle, &rdfds);
					
                    memset((void *)msg, 0, MAX_WIS_DATA_LEN + sizeof(WisSocketCmd));
					ret = recv(handle, msg, sizeof(WisSocketCmd), 0);
					
					if(ret < 0)
					{
						printf("AMirrorClient::TcpRun recv fail\n");
						goto RECONNECT;
					}
                    
					if(ret == 0)
					{
						if(getsockopt(handle, SOL_SOCKET, SO_ERROR, &error, &errlen) < 0)
						{
							printf("AMirrorClient::TcpRun recv getsockopt fail\n");
							goto RECONNECT;
						}
						
						if(error)
						{
							printf("AMirrorClient::TcpRun recv err=%d\n", error);
							goto RECONNECT;
						}
						
						usleep(10000);
						continue;
					}
                    
                    //消息体
                    if ( 0 != msg->cmdDataLength)
                    {
                        int size = msg->cmdDataLength;
                        while(1)
                        {
                            ret = recv(handle,
                                          ((char*)msg+sizeof(WisSocketCmd))+msg->cmdDataLength-size, size, 0);
                            if (ret <= 0)
                            {
                                goto RECONNECT;
                            }
                            size -= ret;
                            if( size <= 0 )
                                break;
                        }
                    }
                    
                    //检测
                    int checksum = 0;
                    for(int i=sizeof(unsigned int); i < sizeof(WisSocketCmd)+msg->cmdDataLength; i++)
                    {
                        checksum += ((unsigned char*)msg)[i];
                    }
                    
                    if (checksum != (msg->checksum)){
                        goto RECONNECT;
                    }
                    
					retry_count = 0;
                    
                    [self dealWithRecvData:msg];
				}
			}
		}
    RECONNECT:
        reconnectTime++;
        if(reconnectTime >= 30)
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                [MMProgressHUD dismiss];
            });
            
            if([self.navigationController.topViewController isKindOfClass:[ServerChooseViewController class]])
            {
                [self performSelectorOnMainThread:@selector(logText:) withObject:@"连接服务器失败" waitUntilDone:YES];
            }
            else
            {
                [self performSelectorOnMainThread:@selector(popToRootWithError) withObject:nil waitUntilDone:YES];
            }
            
            m_bRunning = NO;
            
            [GlobalInfo sharedInstance].m_CmdSock=0;
            close(sock);
            sock = 0;
            
            return;
        }
        
        [GlobalInfo sharedInstance].m_CmdSock=0;
        
		close(sock);
		sock = 0;
		usleep(100000);
	}
    
	if(sock)
	{
        [GlobalInfo sharedInstance].m_CmdSock=0;

		close(sock);
	}
    
    free(msg);
}

-(void)dealWithRecvData:(WisSocketCmd *)cmd
{
    switch(cmd->cmdId)
    {
            /* login  */
        case WIS_CMD_USER_LOGIN:
        {
            int ret;
            if ( cmd->cmdDataLength > 0 )
            {
                ret = *(int *)cmd->cmdData;
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    [MMProgressHUD dismiss];
                });
                if(ret == 0)
                {
                    [self performSelectorOnMainThread:@selector(logText:) withObject:@"登录成功" waitUntilDone:NO];
                    
                    [GlobalInfo sharedInstance].remoteArray = [NSMutableArray array];
                    
                    [WISInterfaces wis_send_get_devices_cmd:[GlobalInfo sharedInstance].m_CmdSock];
                    
                    if(remoteDeviceTimer == nil && ![remoteDeviceTimer isValid])
                    {
                        remoteDeviceTimer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(getRemoteDeviceTimerMethod) userInfo:nil repeats:YES];
                        
                        [[NSRunLoop mainRunLoop] addTimer:remoteDeviceTimer forMode:NSDefaultRunLoopMode];
                    }
                    
                    [self performSelectorOnMainThread:@selector(enterUPNPController) withObject:nil waitUntilDone:NO];
                }
                else
                {
                    [self performSelectorOnMainThread:@selector(logText:) withObject:@"登录失败" waitUntilDone:NO];
                }
            }
            else
            {
                [self performSelectorOnMainThread:@selector(logText:) withObject:@"登录失败" waitUntilDone:NO];
            }
            
            break;
        }
        /* bind  */
        case WIS_CMD_USER_BIND:
        {
            int ret;
            if ( cmd->cmdDataLength > 0 )
                ret = *(int *)cmd->cmdData;
            break;
        }
            
        /* unbind */
        case WIS_CMD_USER_UNBIND:
        {
            int ret;
            if ( cmd->cmdDataLength > 0 )
                ret = *(int *)cmd->cmdData;
            break;
        }

        /* get devices list  */
        case WIS_CMD_USER_GET_DEVICES:
        {
            wis_user_dev_list *list = NULL;
            if ( cmd->cmdDataLength > 0 )
            {
                list = (wis_user_dev_list *)cmd->cmdData;

                dispatch_sync(dispatch_get_main_queue(), ^{
                    [_upnpController remoteDeviceHasReached:list]; });
            }
            
            break;
        }

        /* get device  info*/
        case WIS_CMD_USER_GET_DEVICE_INFO:
        {
            wis_user_dev_info *dev = NULL;
            if ( cmd->cmdDataLength > 0 )
                dev = (wis_user_dev_info *)cmd->cmdData;
            
            
            break;
        }
        case WIS_CMD_USER_HEART_BEAT:
        {
            [WISInterfaces wis_send_heartbeat_cmd:[GlobalInfo sharedInstance].m_CmdSock];
            
            break;
        }
            
        //add by anson 14-03
        case WIS_CMD_USER_PRIVATE:
        {
            int ret = -1;
            if ( cmd->cmdDataLength > 0 )
                ret = *(int *)cmd->cmdData;
            DLog("WIS_CMD_USER_PRIVATE %s ret=%d\n", ret?"failed":"succeed", ret);
            break;
        }
            
        case WIS_CMD_RESULT:
        {
            DLog("===== %s receive cmd : WIS_CMD_RESULT ===== \n", __FUNCTION__);
            
            int len = cmd->cmdDataLength - sizeof(wis_result);
            wis_result * result = (wis_result *)cmd->cmdData;
            DLog("%s  uuid[%s] len[%d]\n", __FUNCTION__, result->session_id, len);
            int i;
            for(i=0; i<len; ++i)
                DLog("result[%d]=0x%.2x\n", i, result->data[i]);
            
            break;
        }
            
        case WIS_CMD_TO_USER:
        {
            DLog("===== %s receive cmd : WIS_CMD_TO_USER ===== \n", __FUNCTION__);
            
            if ( cmd->cmdData && cmd->cmdDataLength >= 32 )
            {
                printf("from dev[%s]\n", cmd->cmdData);
                int len = cmd->cmdDataLength - 32;
                //int i;
				DLog("to_user dlen = %d\n", len);
				UserCmdRet_t *cmdRet = (UserCmdRet_t*)(((wis_result*)cmd->cmdData)->data);
				if (cmdRet->cmd == 0x1000)
				{
					SysInfo_t *sys = (SysInfo_t*)cmdRet->data;
					DLog("[cmdid=0x%x,stat=%d,data_len=%d]:\n", cmdRet->cmd, cmdRet->stat, cmdRet->data_len);
					DLog("-->name=%s\n",sys->name);
					DLog("-->hw_ver=%s\n",sys->hw_ver);
					DLog("-->sw_ver=%s\n",sys->sw_ver);
					DLog("-->mac_addr=%s\n",sys->mac_addr);
					DLog("-->local_ip_addr=%s\n",sys->local_ip_addr);
					DLog("-->public_ip_addr=%s\n",sys->public_ip_addr);
					DLog("-->http_port=%s\n",sys->http_port);
					DLog("-----------------\n ");
				}else{
					
                    NSString *jsonStr = [NSString stringWithCString:cmdRet->data encoding:NSUTF8StringEncoding];
                    DLog("[cmdid=0x%x, stat=%d, data_len=%d]:\n %@\n",
                              cmdRet->cmd, cmdRet->stat, cmdRet->data_len, jsonStr);
                    
                    
				}
				
                // for(i=0; i<len; ++i)
                //     DEBUG_MSG("data[%d]=0x%.2x\n", i, cmd->cmdData[32+i], cmd->cmdData[32+i]);
            }
            break;
        }

            
        default:
        {
        	int i;
            DLog("===== %s unknown cmd : 0x%x len=%d ===== \n",
                      __FUNCTION__, cmd->cmdId, cmd->cmdDataLength);
       	 	for(i = 0; i < cmd->cmdDataLength; ++i)
            	DLog("data[%d]=0x%.2X=[%c]\n",
                          i, cmd->cmdData[i], cmd->cmdData[i]);
        }
        break;

    }
}

-(void)getRemoteDeviceTimerMethod
{
    [WISInterfaces wis_send_get_devices_cmd:[GlobalInfo sharedInstance].m_CmdSock];
    
}

-(void)attempToCreateThread
{
    while ([GlobalInfo sharedInstance].m_CmdSock != 0) {
        [NSThread sleepForTimeInterval:0.1];
    }
    
    NSLog(@"create thread");
    
    if(![m_recvThread isCancelled])
    {
        [m_recvThread cancel];
    }
    m_recvThread = nil;
    
    m_bRunning = YES;
    m_recvThread = [[NSThread alloc] initWithTarget:self selector:@selector(TCPRun) object:nil];
    [m_recvThread start];
}
/* replace by GlobalInfo
-(NSString *)getUniqueID
{
//    NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
//    
//    NSMutableString * mutableString = [NSMutableString stringWithString:adId];
//    [mutableString replaceOccurrencesOfString:@"-" withString:@"" options:NSCaseInsensitiveSearch range: NSMakeRange(0, [mutableString length])];
//    
//    return mutableString;

    
    NSString* openUDID = [OpenUDID value];
    NSString * retStr = [NSString stringWithFormat:@"ios%@",[openUDID substringToIndex:28]];
    return retStr;
}
*/
@end
